package com.example.bigdata.scala.集合

import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}


/**
  *  集合: 可变（mutable） & 不可变（immutable）
  *
  */
object Demo {
    def main(args: Array[String]): Unit = {
        //ArrayDemo()
        //ListDemo()
        //QueueDemo()
        //SetDemo()
        //MapDemo()
        //TupleDemo()
        //MethodDemo()
        //WorldCountDemo()
        MethodDemo01()
    }

    def MethodDemo01(): Unit ={
        val list = List(1,2,3,4)
        //从左向右 两两相加 (((1+2)+3)+4)
        println(list.reduce(_ + _))
        // reduce == reduceLeft  从左 向 右 运算
        println(list.reduceLeft(_ + _))
        // 从右 向 左 运算
        println(list.reduceRight(_ + _))

        // 折叠 fold  初始值 100 与集合每个元素进行减法操作
        println(list.fold(100)(_-_))
        // fold == foldLeft
        println(list.foldLeft(100)(_-_))

        /**  源码分析
          *  reverse => 4,3,2,1
          *  foldLeft ==> (((10-4)-3)-2)-1
          *  foldRight ==> (1-(2-(3-(4-10))) == 8
          */
        println(list.foldRight(10)(_-_))

        /**
          *  将两个Map进行合并，相同key做累加，不同key直接增加
          *  a->4,b->2,c->5,d->1
          */
        val map1 = mutable.Map("a"->1,"b"->2,"c"->3)
        val map2 = mutable.Map("a"->3,"c"->2,"d"->1)
        val mapFold: mutable.Map[String, Int] = map1.foldLeft(map2)((map, t) => {
            // "a" -> 1
            // map集合设置的方式  map(key)=value
            map(t._1) = map.getOrElse(t._1, 0) + t._2
            map
        })
        println(mapFold)



    }

    def WorldCountDemo(): Unit ={
        val lineList: List[(String, Int)] = List(
            ("Hello Scala World", 4),
            ("Hello World", 3),
            ("Hello Hadoop", 2),
            ("Hello Hbase", 1))
        // 将List 拆分 成单词数据
        val flatMapList: List[(String, Int)] = lineList.flatMap(t => {
            val line = t._1.split(" ")
            line.map(w => (w, t._2))
        })
        // 对分词进行分组
        val groupWordMap: Map[String, List[(String, Int)]] = flatMapList.groupBy(t=>{t._1})
        // 统计分词总数
        /*val wordToSumMap: Map[String, Int] = groupWordMap.map(t => {
            val countList: List[Int] = t._2.map(tt => tt._2)
            (t._1, countList.sum)
        })*/
        val wordToSumMap: Map[String, Int] = groupWordMap.mapValues(datas=>datas.map(tt=>tt._2).sum)
        // 对分词集合进行排序
        val wordSortList: List[(String, Int)] = wordToSumMap.toList.sortWith((left,right) => (left._2>right._2))
        // 获取分词集合升序、前三
        println(wordSortList.take(3))
        
    }
    def MethodDemo(): Unit ={
        // 集合常用方法
        val list1 = List(1,3,3,2,4,5,2,6)
        print(list1.max)
        print(list1.min)
        print(list1.sum)
        // 乘积
        println(list1.product)
        // 反转(无排序)
        println(list1.reverse)

        // 分组 按照元素首字母分组  s.substring(0,1) 截取s变量第0->1 索引的数据
        val stringList = List("11","12","21","22")
        val stringToStrings: Map[String, List[String]] = stringList.groupBy(s=>{s.substring(0,1)})
        //wordToListMap1.foreach(t=>{println(t._1 +"="+t._2)})
        // 偶数分组
        val intToInts: Map[Int, List[Int]] = list1.groupBy(x=>{x % 2})
        intToInts.foreach(x=>{println(x._1+"="+x._2)})

        // 排序 (按照指定规则排序)
        val stringList1 = List("11","23","14","22")
        val sortStrings: List[String] = stringList1.sortBy(t=>{t.substring(1)})
        println(sortStrings.mkString(","))

        // 升序
        println(list1.sortWith((x, y) => {
            x < y
        }))
        // 降序
        println(list1.sortWith((x, y) => {
            x > y
        }))

        // 对 stringList1 按照第二位大小进行排序 如降序: 14，23，22，11
        val strings1: List[String] = stringList1.sortWith((Left, Right) => {
            Left.substring(1).toInt > Right.substring(1).toInt
        })
        println(strings1.mkString(","))
        // 迭代
        //list1.iterator
        // 映射  map
        val tuples: List[(Int, Int)] = list1.map(x=>(x,1))
        val intToTuples: Map[Int, List[(Int, Int)]] = tuples.groupBy(t=>t._1)
        val intToInt: Map[Int, Int] = intToTuples.map(x=>(x._1,x._2.size))
        println(intToInt.mkString("\t::\t"))
        // 获取 集合 前n个元素
        list1.take(10)
        // 统计单词出现次数，并降序排列，取前三名打印
        val wordList = List("hello","Scala","hello","world","Hbase","hadoop","Kafka","Scala","world")
        // 将相同单词放置一组
        val wordToListMap: Map[String, List[String]] = wordList.groupBy(word=>word)
        println("wordToListMap : "+wordToListMap.mkString(","))

        // 将数据结构转换
        val wordToCountMap: Map[String, Int] = wordToListMap.map(x=>{(x._1,x._2.size)})
        // 降序
        val sortList = wordToCountMap.toList.sortWith((left,right)=>(left._2 > right._2))
        println(sortList.mkString(","))
        val resultList = sortList.take(3)
        println(resultList.mkString(","))

        // TODO 扁平化操作
        // 将一个整体的内容拆成一个个的个体
        val lineList = List("hello world","hello scala","hello hadoop")
        val flatMapList: List[String] = lineList.flatMap(x=>x.split(" "))
        val sortMapList = flatMapList.groupBy(x => x).map(x=>{(x._1,x._2.size)}).toList.sortWith((left,right)=>left._2>right._2)
        println(sortMapList)
        println(lineList)
        println(flatMapList)

        // TODO 拉链 : ZIP
        val listzip01 = List(1,2,3,7)
        val listzip02 = List(4,5,6,7)
        val listzip03: List[(Int, Int)] = listzip01.zip(listzip02)
        println(listzip03.mkString(","))

        // TODO 集合并集 : union
        val listunion01 = listzip01.union(listzip02)
        println(listunion01)
        // TODO 交集
        val intersectList: List[Int] = listzip01.intersect(listzip02)
        println(intersectList)

        // TODO  差集 diff
        val diffList01: List[Int] = listzip01.diff(listzip02)
        println(diffList01)
    }
    def TupleDemo(): Unit ={
        //Tuple:元组  使用小括号将不相关的数据关联起来，形成一个整体使用
        // 元素数据 最多可存储 22个数据
        // empid,email,ordernum
        val tuple: (String, Int, String) = ("zhangsan",1111,"xxxxx")
        //访问元组中的数据
        println(tuple._1)
        println(tuple._2)
        println(tuple._3)
        // 元组循环
        for (elem <- tuple.productIterator) {
            println(elem)
        }
        // 如果元组中院上诉个数为2，那么称之为对偶，类似于Map中键值对
        val tuple1: (Int, String) = (1,"zhangsan")
        val tupleMap: Map[Int, String] = Map((1,"zhangsan"))
        tupleMap.foreach(t=>{println(t._1+"="+t._2)})
    }
    def MapDemo(): Unit ={
        // Map 集合 : k - v 对
        val map: Map[String, Int] = Map(
            "a" -> 1,
            "b" -> 2,
            "c" -> 3
        )
        // 添加元素
        val map1 = map + ("d" -> 4)
        println(map.mkString(","))
        println(map1.mkString(","))
        println("map vs map1 = " + map == map1)
        // 删除元素
        map1 - ("d")
        // 修改数据
        val map2 = map1.updated("b",5)
        println(map2.mkString(","))

        // 可变Map集合
        val mmap: mutable.Map[String, Int] = mutable.Map("a"->1,"b"->2)

        // 循环遍历
        /**
          *  Scala 为了防止 空指针问题，提供了一个特殊类Option ， 有两个对象 Some；None 。
          *  如果确实没有数据，为了不出异常，option 提供了有默认值的方法
          *  map2.get("xxx").getOrElse("yyy")  xxx 如果有值 则返回，没有值 则 xxx="yyy"
          */

    }
    def SetDemo(): Unit ={
        // Set 集合: 无序、不重复
        val set: Set[Int] = Set(1,2,4,1,2,6)
        // 增加
        println(set + 11)
        println(set - 1)
        println(set.mkString(","))

        // 可变 Set集合(mutable)
        val mset = mutable.Set(1,2,3,4)
        mset.add(5)
        println(mset)
    }
    def QueueDemo(): Unit ={

    }
    def ListDemo(): Unit ={
        // Seq 序列
        val list1 = List(1,2,3,4)
        // 通过索引查询
        println(list1(0))
        // 增加数据
        val list2 = list1:+1
        println(list2.mkString(","))

        val list3 = List(6,7,8,9)
        val list4 = 9 :: list3 :: list1
        val list5 = 9 :: list3 ::: list1
        println(list4.mkString(","))
        println(list5.mkString(","))
        //特殊List集合 : 空集合
        println(List())
        println(Nil)
        println(1 :: 2 :: 3 :: Nil)

        // 修改
        val list6: List[Int] = list1.updated(2,5)
        // 删除数据
        list1.drop(2)
        // 查询数据
        list1.foreach(println)

        // TODO 可变集合
        val mlist: ListBuffer[Int] = ListBuffer(1,2,3,4)
//        mlist.insert()
//        mlist.updated()
//        mlist.drop()
//        mlist.remove()

        //list 头部
        println(mlist.head)
        // 尾部
        println(mlist.tail)
        // 最后一个
        println(mlist.last)
        // 初始化 (除了最后一个)
        println(mlist.init)

    }
    def ArrayDemo(): Unit ={
        val ints: Array[Int] = Array(1, 2, 3, 4)
        //
        // 使用小括号，增加索引的方式来访问数组
        println(ints(0))
        println(ints.length)
        // 将数组转换为字符串
        println(ints.mkString(","))

        // 打印每个元素
        def printlnXXX(i:Int): Unit ={
            println(i)
        }
        // foreach 接收一个方法 (逐级简化)
//        ints.foreach(printlnXXX)
//        ints.foreach((i:Int)=>{println(i)})
//        ints.foreach((i)=>{println(i)})
//        ints.foreach(println(_))
        ints.foreach(println)
        for (elem <- ints){
            println(elem)
        }

        // 增加元素 (创建一个新的数组) ，但不对
        ints:+(51)
        //修改数据
        ints.update(1,5)
        println(ints.mkString(","))

        // 可变数组
        val arrbuffer = ArrayBuffer(5,6,7,8,9)
        // 添加元素，到指定位置
        arrbuffer.insert(1,9)
        // 添加元素到最后
        arrbuffer+=(99)
        arrbuffer.append(100)
        arrbuffer.foreach(println)

        // 删除数据
        //arrbuffer.remove(1)
        // 从索引1开始删除2个元素
        arrbuffer.remove(1,2)
        println(arrbuffer.mkString(","))
        // 可变数组  <--> 不可变数组
        // 可变 转 不可变
        val array: Array[Int] = arrbuffer.toArray
        // 不可变 转 可变数组
        val buffer: mutable.Buffer[Int] = array.toBuffer


    }

}